package com.example.bigevent.controller;

import com.example.bigevent.pojo.LoginUser;
import com.example.bigevent.pojo.PageBean;
import com.example.bigevent.pojo.Result;
import com.example.bigevent.pojo.User;
import com.example.bigevent.pojo.system.Role;
import com.example.bigevent.service.UserService;
import com.example.bigevent.utils.CaptchaGenerator;
import com.example.bigevent.utils.JwtUtil;
import com.example.bigevent.utils.Md5Util;
import com.example.bigevent.utils.ThreadLocalUtil;
import com.example.bigevent.validation.ValidationGroup;
import org.hibernate.validator.constraints.URL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private PasswordEncoder passwordEncoder;

    private String captcha;

    /**
     *  注册
     */
    @PostMapping("/register")
    public Result register(@Validated(ValidationGroup.RegisterAndLogin.class) User user,@RequestParam("captcha") String captcha){
        //校验验证码是否正确
        String s = stringRedisTemplate.opsForValue().get(captcha);
        if(!captcha.equals(s)){
            return Result.error("验证码错误");
        }
        User u = userService.findByUserName(user.getUsername());
        if(u!=null){
            return Result.error("用户名已占用");
        }
        userService.register(user);
        return Result.success();
    }

    /**
     * 登录
     */
    @PostMapping("/login")
    public Result<String> login(@Validated(ValidationGroup.RegisterAndLogin.class) User user,@RequestParam("captcha") String captcha){
        //校验验证码是否正确
        String s = stringRedisTemplate.opsForValue().get(captcha);
        if(!captcha.equals(s)){
            return Result.error("验证码错误");
        }
        //校验用户名密码
        UsernamePasswordAuthenticationToken authentication=new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authentication);
        if(authenticate==null){
            return Result.error("用户名或密码错误");
        }
        //认证成功，将用户信息存入redis
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        redisTemplate.opsForValue().set("big-event:login:user:"+loginUser.getUser().getId(),loginUser,12,TimeUnit.HOURS);
        //登录成功，生成jwt令牌
        Map<String, Object> claims=new HashMap<>();
        claims.put("id",loginUser.getUser().getId());
        claims.put("username",loginUser.getUser().getUsername());
        String token = JwtUtil.genToken(claims);
        //将令牌存放到redis
        stringRedisTemplate.opsForValue().set("big-event:token:user:"+loginUser.getUser().getId(),token,12, TimeUnit.HOURS);
        return Result.success(token);
    }

    /**
     * 获取验证码
     */
    @GetMapping("/captcha")
    public Result<String> captcha() throws IOException {
        String captchaOriginal=captcha;
        //生成验证码
        captcha = CaptchaGenerator.generateRandomText(4);
        String base64Image  = Base64.getEncoder().encodeToString(CaptchaGenerator.generateCaptcha(captcha));
        String imageSrc = "data:image/png;base64," + base64Image;
        //将验证码存入redis
        stringRedisTemplate.opsForValue().set(captcha,captcha,1,TimeUnit.MINUTES);
        //删除原先的验证码
        if(captchaOriginal!=null){
            stringRedisTemplate.delete(captchaOriginal);
        }
        return Result.success(imageSrc);
    }

    /**
     * 获取用户详细信息
     */
    @GetMapping("/userInfo")
    @PreAuthorize("hasAuthority('user:query')")
    public Result<User> userInfo(){
        Map<String, Object> map = ThreadLocalUtil.get();
        String username = (String) map.get("username");
        User user = userService.findByUserName(username);
        return Result.success(user);
    }

    /**
     * 获取后台所有用户信息
     */
    @GetMapping("/sys/userInfo")
    @PreAuthorize("hasAuthority('system:user:query')")
    public Result<PageBean<User>> sysUserInfo(Integer pageNum,Integer pageSize,User user){
        PageBean<User> pageBean=userService.sysUserInfo(pageNum,pageSize,user);
        return Result.success(pageBean);
    }

    /**
     * 获取用户的角色
     */
    @GetMapping("/roles")
    public Result<List<Role>> roles(){
        List<Role> list=userService.roles();
        return Result.success(list);
    }

    /**
     * 更新用户基本信息，更新后台用户
     *
     */
    @PutMapping("/update")
    @PreAuthorize("hasAnyAuthority('user:update','system:user:update')")
    public Result update(@RequestBody @Validated(ValidationGroup.Update.class) User user){
        userService.update(user);
        return Result.success();
    }

    /**
     * 更新用户头像
     */
    @PatchMapping("/updateAvatar")
    @PreAuthorize("hasAuthority('user:update')")
    public Result updateAvatar(@RequestParam(value ="avatarUrl") @URL String avatarUrl){
        User user=new User();
        user.setUserPic(avatarUrl);
        userService.update(user);
        return Result.success();
    }

    /**
     * 更新用户密码
     */
    @PatchMapping("/updatePwd")
    @PreAuthorize("hasAuthority('user:update')")
    public Result updatePwd(@RequestBody Map<String,String> params){
        String oldPwd = params.get("old_pwd");
        String newPwd = params.get("new_pwd");
        String rePwd = params.get("re_pwd");
        //校验密码
        if(!StringUtils.hasLength(oldPwd)||!StringUtils.hasLength(newPwd)||!StringUtils.hasLength(rePwd)){
            return Result.error("密码不能为空");
        }
        if(newPwd.length()<5||newPwd.length()>16){
            return Result.error("密码必须是5-16位非空字符");
        }
        if(!newPwd.equals(rePwd)){
            return Result.error("确认密码错误");
        }
        //查询数据库看原密码是否正确
        Map<String,Object> map=ThreadLocalUtil.get();
        User loginUser = userService.findById((Integer) map.get("id"));
        if(!passwordEncoder.matches(oldPwd,loginUser.getPassword())){
            return Result.error("原密码错误");
        }
        //更新密码
        User user=new User();
        user.setPassword(newPwd);
        userService.update(user);
        //将redis存的token和用户信息删除
        Map<String,Object> map1=ThreadLocalUtil.get();
        stringRedisTemplate.delete("big-event:token:user:"+map1.get("id"));
        redisTemplate.delete("big-event:login:user:"+map1.get("id"));
        return Result.success();
    }

    /**
     * 删除后台用户
     */
    @DeleteMapping("/sys/delete")
    @PreAuthorize("hasAuthority('system:user:delete')")
    public Result sysDelete(Integer id){
        userService.sysDelete(id);
        return Result.success();
    }
}
